//+FHDR-------------------------------------------------------------------------
//            __     __ __                  ____     ___ ___
//           |  |   |  /__| ____ ___ ___   /    \   /  ____/
//           |  \___/  |  /   __    __   \/  __  \ /  /
//           |   ___   |  |  /  \  /  \     /__\  (  <
//           |  /   \  |  |  |  |  |  |    /    \     \____
//           |__|   |__ __ __|  |__|  |___/      \__ __ ___\ 2.0                     
//------------------------------------------------------------------------------
//-- Module Name     :    fp_action_exe
//-- Hierarchy       :    frame_process - * - fp_action_exe
//-- Description     :    修改：配合乒乓、帧信息不经过本模块，去掉统计接口，去掉VLAN操作、简化操作、简化接口                                             
//                                                                              
//-- Last Modified   : 2013-02-26 15:34
//-- Revision history:                                                          
//     Date               Author       Description                              
//     2012-12-20 19:32   Tiger          Initialize code
//     2012-6-11          lhb          修改387行des_node_id号读使能条件
//-FHDR-------------------------------------------------------------------------

`timescale 1ns/100ps

module fp_action_exe
                    (       
                     input clk,
                     input rst_n, 
                     //指令码接口
                     output reg action_data_rden,
                     input wire action_data_empty,
                     input [97:0] action_fifo_q,
                     //直接捕获的帧
                     input direct_capture,
                     output reg action_fifo_rden,
                     
                      //和frame_len_fifo的接口
                     input frame_len_fifo_empty,
                     output reg frame_len_fifo_rden,
                     input [10:0] frame_length_i,

                     //和frame_info_fifo的接口
                     output reg frame_info_fifo_wren,
                     output wire [31:0] frame_info_o,
                     input wire frame_info_fifo_full,

                     //和总线控制模块之间的信号
                     output reg action_en,
                     output wire[75:0] action_fifout,

// **********************************************************
//                   input broadcast_trans_end,
//**********************************************************/
                     input wire[7:0]  insert_dest_node,   //插入帧想要进入的目的节点号
                     output reg des_node_ren,
                     input [2:0]  pri_insert,
                     input  insert_fifo_empty,
                     output reg insert_fifo_rden,
                     input  insert_fifo_q
                    );
//帧的处理可以分为：插入帧和非插入帧
//插入帧需要读出帧的长度信息，然后将帧信息交给调度
//非插入帧需要读出帧的长度信息，分析帧的action信息，然后交给调度
parameter IDLE                 = 3'b001;
parameter WR_FRAME_INFO_FIFO   = 3'b010;     
parameter WR_INSERT_FRAME_INFO = 3'b100;

reg[2:0]   action_exe_cstate;
reg[2:0]   action_exe_nstate;

//寄存action_fifo_q中的数据
reg       is_flow_ctrl_r     ;
reg[ 6:0] flow_ctrl_num      ;
reg       discard_r          ;
reg       duplicate_to_cpu_r ;
reg       redirect_to_cpu_r  ;
reg       pri_assign         ;
reg[ 2:0] ffp_pri            ;  //流分类指定的优先级
reg[ 2:0] operation_r        ;
reg[ 4:0] word_offset_r      ;
reg[ 1:0] layer_in           ;
reg[31:0] mask_r             ;
reg[31:0] value_r            ;
reg[ 3:0] layer3             ;
reg[ 5:0] layer4             ;

reg       valid_bit          ;
reg[ 2:0] pri                ;
reg[10:0] frame_length_r     ;



reg       insert_frame_flag    ;

wire[5:0] layer_start  ;
wire[5:0] word_offset  ;
//三段式状态机，格式化次态向现态过度
always @ (posedge clk or negedge rst_n)
if (rst_n==1'b0)
  action_exe_cstate <= IDLE;  
else 
  action_exe_cstate <= action_exe_nstate;

//组合逻辑，状态跳转条件判断
always @ ( * )
begin
  case(action_exe_cstate)
    IDLE: //非插入帧需要等流分类的结果输出之后完成
          //  插入帧不需通过流分类
      if(insert_fifo_q && !frame_len_fifo_empty && !insert_fifo_empty)
        action_exe_nstate = WR_INSERT_FRAME_INFO;
      else if(!action_data_empty && !insert_fifo_q && !frame_len_fifo_empty && !insert_fifo_empty) 
        action_exe_nstate = WR_FRAME_INFO_FIFO; 
      else
        action_exe_nstate = IDLE;
    WR_INSERT_FRAME_INFO: //读出帧长信息
      action_exe_nstate = IDLE;
    WR_FRAME_INFO_FIFO: //将帧信息进行整合，写入frame_info_fifo中（和调度模块的接口）
      action_exe_nstate = IDLE;
    default:
      action_exe_nstate = IDLE;
  endcase
end
//读取指令码fifo

always@(posedge clk or negedge rst_n)
  if(!rst_n)
    action_data_rden <= 1'b0;
  else if(action_exe_nstate == WR_FRAME_INFO_FIFO)
    action_data_rden <= 1'b1;
  else 
    action_data_rden <= 1'b0;

//读捕获标志fifo

always@(posedge clk or negedge rst_n)
  if(!rst_n)
    action_fifo_rden <= 1'b0;
  else if(action_exe_nstate != IDLE && action_exe_cstate == IDLE)
    action_fifo_rden <= 1'b1;
  else 
    action_fifo_rden <= 1'b0;

//寄存操作信息
always @(posedge clk or negedge rst_n )
if(rst_n==1'b0) 
begin
    is_flow_ctrl_r     <= 1'd0 ;
    flow_ctrl_num      <= 7'd0 ;
    discard_r          <= 1'd0 ;
    duplicate_to_cpu_r <= 1'd0 ;
    redirect_to_cpu_r  <= 1'd0 ;
    pri_assign         <= 1'd0 ;
    ffp_pri            <= 3'd0 ;
    operation_r        <= 3'd0 ;
    word_offset_r      <= 5'd0 ;
    layer_in           <= 2'd0 ;
    mask_r             <= 32'd0;
    value_r            <= 32'd0;
    layer3             <= 4'd0 ;
    layer4             <= 6'd0 ;
end
else if(action_exe_nstate == WR_FRAME_INFO_FIFO ) //插入帧不执行流分类的动作
begin     //插入帧不执行流分类指定的操作
    is_flow_ctrl_r     <= action_fifo_q[88];  //是否进行流控
    flow_ctrl_num      <= action_fifo_q[87:81];  //流控号
    discard_r          <= action_fifo_q[80];  //丢弃
    duplicate_to_cpu_r <= action_fifo_q[79];  //复制
    redirect_to_cpu_r  <= action_fifo_q[78] | direct_capture;  //重定向
    pri_assign         <= action_fifo_q[77];  //指定优先级
    ffp_pri            <= action_fifo_q[76:74];  //优先级号
    operation_r        <= action_fifo_q[73:71];  //插入、修改、删除
    word_offset_r      <= action_fifo_q[70:66];  //字偏移
    layer_in           <= action_fifo_q[65:64];  //层号
    mask_r             <= action_fifo_q[63:32];  //掩码
    value_r            <= action_fifo_q[31: 0];  //值
    layer3             <= action_fifo_q[97:94];  //三层起始
    layer4             <= {2'b0,action_fifo_q[97:94]} + {1'b0,action_fifo_q[93:89]};  //四层起始
end

else if(action_exe_nstate == IDLE) 
begin
    is_flow_ctrl_r     <= 1'd0 ;
    flow_ctrl_num      <= 7'd0 ;
    discard_r          <= 1'd0 ;
    duplicate_to_cpu_r <= 1'd0 ;
    redirect_to_cpu_r  <= 1'd0 ;
    pri_assign         <= 1'd0 ;
    ffp_pri            <= 3'd0 ;
    operation_r        <= 3'd0 ;
    word_offset_r      <= 5'd0 ;
    layer_in           <= 2'd0 ;
    mask_r             <= 32'd0;
    value_r            <= 32'd0;
    layer3             <= 4'd0 ;
    layer4             <= 6'd0 ;
end
else 
begin
    is_flow_ctrl_r     <= is_flow_ctrl_r    ;
    flow_ctrl_num      <= flow_ctrl_num     ;
    discard_r          <= discard_r         ;
    duplicate_to_cpu_r <= duplicate_to_cpu_r;
    redirect_to_cpu_r  <= redirect_to_cpu_r ;
    pri_assign         <= pri_assign        ;
    ffp_pri            <= ffp_pri           ;
    operation_r        <= operation_r       ;
    word_offset_r      <= word_offset_r     ;
    layer_in           <= layer_in          ;
    mask_r             <= mask_r            ;
    value_r            <= value_r           ;
    layer3             <= layer3            ;
    layer4             <= layer4            ;
end

/***************************************************************/
//              获得并写入frame_info_fifo中信息
/***************************************************************/
always @(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        valid_bit <= 1'b0;
    else if(action_exe_nstate == IDLE)    
        valid_bit <= 1'b0;
    else if(action_exe_nstate == WR_FRAME_INFO_FIFO &&(action_fifo_q[80]||((action_fifo_q[78] | direct_capture) && !action_fifo_q[79]))
            && !insert_frame_flag)//丢弃帧--重定向非复制帧
        valid_bit <= 1'b0;
    else if(action_exe_nstate == WR_FRAME_INFO_FIFO )
        valid_bit <= 1'b1; 
    else if(action_exe_nstate == WR_INSERT_FRAME_INFO)
        valid_bit <= 1'b1;                                                                        
    else 
        valid_bit <= valid_bit;
end
//输入有8个优先级，输出也是8个优先级
always @ (posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        pri <= 3'd0;
    else if ((action_exe_nstate == WR_FRAME_INFO_FIFO)&&(insert_frame_flag == 1'b0))
    begin
        if (action_fifo_q[77]) begin
            pri <= action_fifo_q[76:74];
        end
        else begin
            pri <= 3'b111;
        end
    end
    else if ((action_exe_nstate == WR_INSERT_FRAME_INFO)&&(insert_frame_flag == 1'b1))
    begin
        pri <= pri_insert;
    end
    else 
      pri <= pri;
end


always @(posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        frame_length_r <= 11'd0;
    else if(action_exe_nstate == WR_FRAME_INFO_FIFO)
    begin
      if(action_fifo_q[73]==1'b1)                      //插入操作
          frame_length_r <= frame_length_i + 11'd4;
      else if(action_fifo_q[72]==1'b1)                 //修改操作
          frame_length_r <= frame_length_i;
      else if(action_fifo_q[71]==1'b1)                 //删除操作
          frame_length_r <= frame_length_i - 11'd4;
      else                                          //无操作
          frame_length_r <= frame_length_i;
    end
    else if(action_exe_nstate == WR_INSERT_FRAME_INFO)
      frame_length_r <= frame_length_i;
    else
        frame_length_r <= frame_length_r;
end

always @(posedge clk or negedge rst_n )
begin
    if(rst_n ==1'b0) 
    begin
        frame_info_fifo_wren <= 1'd0;
    end
    else if(action_exe_nstate == WR_FRAME_INFO_FIFO && !frame_info_fifo_full)
    begin
        frame_info_fifo_wren<= 1'd1;
    end
    else if(action_exe_nstate == WR_INSERT_FRAME_INFO && !frame_info_fifo_full)
    begin
        frame_info_fifo_wren <= 1'd1;
    end
    else  
    begin
        frame_info_fifo_wren<= 1'd0;
    end
end
// assign frame_info_o = (frame_info_fifo_wren)?{valid_bit,dest_port,subnet,userid,pri,frame_length_r,cam_is}:32'h0;
// 修改 by Hbing 8-10--增加流控，将插入帧的目的节点以及插入帧标识写入frame_info_fifo中
assign frame_info_o = (frame_info_fifo_wren)?{insert_frame_flag,insert_dest_node,is_flow_ctrl_r,flow_ctrl_num,valid_bit,pri,frame_length_r}:32'h0;
/***************************************************************/
//              总线接口相关信号输出
//对帧的修改、删除和增加需要由总线模块完成
/***************************************************************/
//将action输出给bus_ctrl模块
always @(posedge clk or negedge rst_n)
if(rst_n==1'b0) 
  action_en      <= 1'd0;
else if(action_exe_nstate == WR_FRAME_INFO_FIFO || action_exe_nstate == WR_INSERT_FRAME_INFO)
  action_en      <= 1'd1;
else   
  action_en      <= 1'd0;

assign layer_start = (layer_in == 2'b10)?layer4:(layer_in==2'b01)?{2'b0,layer3}:6'd0;
assign word_offset = word_offset_r + layer_start;

assign action_fifout = {discard_r &(!insert_frame_flag),duplicate_to_cpu_r,redirect_to_cpu_r,operation_r,word_offset,mask_r,value_r};
            
always @ (posedge clk or negedge rst_n)
  if(rst_n==1'b0)
    insert_fifo_rden <= 1'b0;
  else if (action_exe_nstate == WR_FRAME_INFO_FIFO || action_exe_nstate == WR_INSERT_FRAME_INFO)
    insert_fifo_rden <= 1'b1;
  else
    insert_fifo_rden <= 1'b0;

//读帧长信息fifo使能信号
//无论插入帧还是非插入帧都要读取帧长信息
always @ (posedge clk or negedge rst_n)
  if(rst_n==1'b0)
    frame_len_fifo_rden <= 1'b0;
  else if (action_exe_nstate == WR_FRAME_INFO_FIFO || action_exe_nstate == WR_INSERT_FRAME_INFO)
    frame_len_fifo_rden <= 1'b1;
  else
    frame_len_fifo_rden <= 1'b0;
//des_node_id号只有插入帧才有
always @ (posedge clk or negedge rst_n)
  if(rst_n==1'b0)
    des_node_ren <= 1'b0;
  else if (/* action_exe_nstate == WR_FRAME_INFO_FIFO ||  */action_exe_nstate == WR_INSERT_FRAME_INFO)
    des_node_ren <= 1'b1;
  else
    des_node_ren <= 1'b0;

always @ (posedge clk or negedge rst_n)
if(rst_n==1'b0)
  insert_frame_flag <= 1'b0;
else if (action_exe_cstate == IDLE && !insert_fifo_empty)
  insert_frame_flag <= insert_fifo_q;
else if (action_exe_cstate == IDLE)
  insert_frame_flag <= 1'b0;
else
  insert_frame_flag <= insert_frame_flag;
  
`ifndef ASIC
//-----------mark debug------------
(*mark_debug = "true"*) reg [31:0] fp_action_in_cnt;

always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        fp_action_in_cnt <= 32'd0;
    end
    else if (action_data_rden) begin
        fp_action_in_cnt <= fp_action_in_cnt + 32'b1;
    end
    else begin
        fp_action_in_cnt <= fp_action_in_cnt;
    end
end

(*mark_debug = "true"*) reg [31:0] fp_action_out_cnt;

always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        fp_action_out_cnt <= 32'd0;
    end
    else if (action_en) begin
        fp_action_out_cnt <= fp_action_out_cnt + 32'b1;
    end
    else begin
        fp_action_out_cnt <= fp_action_out_cnt;
    end
end
`endif
endmodule
